﻿#include <graphics.h>
#include <conio.h>
#include <iostream>
#include <vector>
#include <queue>
#include <ctime>
using namespace std;

// 定义常量
const int MAP_WIDTH = 31;
const int MAP_HEIGHT = 28;
const int CELL_SIZE = 20;
const int PACMAN_SPEED = 6;

// 定义地图元素
enum MapElement {
    EMPTY = 0,      // 空白
    WALL = 1,       // 墙壁
    BEAN = 2,       // 豆子
    ENERGY_BEAN = 3 // 能量豆
};

// 吃豆人结构体
struct Pacman {
    int x, y;
    int dir;  // 方向，0:上，1:右，2:下，3:左
    int lives;
    int score;
};

// 幽灵结构体
struct Ghost {
    int x, y;
    int dir;
    bool isScared;  // 幽灵是否处于害怕状态
    int scaredTimer;  // 害怕状态计时器
};

// 地图类
class GameMap {
private:
    MapElement map[MAP_WIDTH][MAP_HEIGHT];
    int totalBeans; // 豆子总数，用于判断游戏胜利条件

public:
    // 初始化地图
    void initMap() {
        // 清空地图
        for (int i = 0; i < MAP_WIDTH; i++) {
            for (int j = 0; j < MAP_HEIGHT; j++) {
                map[i][j] = EMPTY;
            }
        }

        // 设置墙壁 - 设计一个更接近经典吃豆人游戏的地图
        setupWalls();

        // 设置豆子和能量豆
        setupBeans();

        // 计算豆子总数
        countBeans();
    }

    // 设置墙壁
    void setupWalls() {
        // 边界墙壁
        for (int i = 0; i < MAP_WIDTH; i++) {
            map[i][0] = WALL;
            map[i][MAP_HEIGHT - 1] = WALL;
        }
        for (int j = 0; j < MAP_HEIGHT; j++) {
            map[0][j] = WALL;
            map[MAP_WIDTH - 1][j] = WALL;
        }

        // 经典吃豆人地图布局
        // 水平墙壁
        for (int i = 3; i < 28; i++) {
            if (i != 15) {
                map[i][3] = WALL;
                map[i][24] = WALL;
            }
        }

        for (int i = 3; i < 13; i++) {
            map[i][6] = WALL;
            map[i][12] = WALL;
            map[i][16] = WALL;
        }

        for (int i = 18; i < 28; i++) {
            map[i][6] = WALL;
            map[i][12] = WALL;
            map[i][16] = WALL;
        }

        for (int i = 3; i < 28; i++) {
            if (i != 15) {
                map[i][9] = WALL;
                map[i][19] = WALL;
            }
        }

        // 垂直墙壁
        for (int j = 3; j < 25; j++) {
            map[3][j] = WALL;
            map[27][j] = WALL;
        }

        for (int j = 3; j < 7; j++) {
            map[13][j] = WALL;
            map[17][j] = WALL;
        }

        for (int j = 3; j < 10; j++) {
            map[8][j] = WALL;
            map[22][j] = WALL;
        }

        for (int j = 10; j < 20; j++) {
            map[8][j] = WALL;
            map[22][j] = WALL;
            map[13][j] = WALL;
            map[17][j] = WALL;
        }

        for (int j = 13; j < 25; j++) {
            if (j != 15 && j != 16) {
                map[3][j] = WALL;
                map[27][j] = WALL;
            }
        }

        for (int j = 20; j < 25; j++) {
            map[8][j] = WALL;
            map[22][j] = WALL;
        }

        // 幽灵房
        for (int i = 11; i < 20; i++) {
            map[i][11] = EMPTY; // 入口
            map[i][12] = EMPTY;
            map[i][13] = EMPTY;
            map[i][14] = EMPTY;
        }
        map[15][11] = EMPTY; // 幽灵房入口

        // 中间门形
        map[14][11] = EMPTY;
        map[15][11] = EMPTY;
        map[16][11] = EMPTY;

        // 顶部弧形
        for (int i = 6; i < 12; i++) map[i][5] = WALL;
        for (int i = 19; i < 25; i++) map[i][5] = WALL;

        // 底部弧形
        for (int i = 6; i < 12; i++) map[i][22] = WALL;
        for (int i = 19; i < 25; i++) map[i][22] = WALL;
    }

    // 设置豆子和能量豆
    void setupBeans() {
        totalBeans = 0;

        // 在空白位置放置豆子
        for (int i = 1; i < MAP_WIDTH - 1; i++) {
            for (int j = 1; j < MAP_HEIGHT - 1; j++) {
                if (map[i][j] == EMPTY) {
                    // 95%概率放置普通豆子
                    if (rand() % 20 < 19) {
                        map[i][j] = BEAN;
                        totalBeans++;
                    }
                    // 5%概率放置能量豆
                    else {
                        map[i][j] = ENERGY_BEAN;
                        totalBeans++;
                    }
                }
            }
        }

        // 清除吃豆人初始位置的豆子
        map[15][23] = EMPTY;
        map[15][4] = EMPTY;
    }

    // 计算豆子总数
    void countBeans() {
        totalBeans = 0;
        for (int i = 0; i < MAP_WIDTH; i++) {
            for (int j = 0; j < MAP_HEIGHT; j++) {
                if (map[i][j] == BEAN || map[i][j] == ENERGY_BEAN) {
                    totalBeans++;
                }
            }
        }
    }

    // 获取地图元素
    MapElement getElement(int x, int y) const {
        if (x >= 0 && x < MAP_WIDTH && y >= 0 && y < MAP_HEIGHT) {
            return map[x][y];
        }
        return WALL; // 超出边界视为墙壁
    }

    // 设置地图元素
    void setElement(int x, int y, MapElement element) {
        if (x >= 0 && x < MAP_WIDTH && y >= 0 && y < MAP_HEIGHT) {
            map[x][y] = element;
            if (element == EMPTY && (map[x][y] == BEAN || map[x][y] == ENERGY_BEAN)) {
                totalBeans--;
            }
        }
    }

    // 检查豆子是否被吃完
    bool isMapClear() const {
        return totalBeans == 0;
    }

    // 绘制地图
    void draw() const {
        for (int i = 0; i < MAP_WIDTH; i++) {
            for (int j = 0; j < MAP_HEIGHT; j++) {
                int x = i * CELL_SIZE;
                int y = j * CELL_SIZE;

                switch (map[i][j]) {
                case WALL:
                    setlinecolor(0xCCA4E3);
                    solidrectangle(x, y, x + CELL_SIZE, y + CELL_SIZE);
                    break;

                case BEAN:
                    setfillcolor(0xF2F2B0);
                    solidcircle(x + CELL_SIZE / 2, y + CELL_SIZE / 2, 3);
                    break;

                case ENERGY_BEAN:
                    setfillcolor(0xBCA590);
                    solidcircle(x + CELL_SIZE / 2, y + CELL_SIZE / 2, 5);
                    break;

                default:
                    // 空白区域不绘制
                    break;
                }
            }
        }
    }
};

// 游戏类
class Game {
private:
    GameMap map;
    Pacman pacman1, pacman2;
    Ghost ghost;
    bool gameOver;
    bool gameWin;
    IMAGE pacmanImage1;
    IMAGE pacmanImage2;
    IMAGE ghostImage;
    IMAGE scaredGhostImage;

public:
    Game() : gameOver(false), gameWin(false) {
        // 初始化随机数种子
        srand(static_cast<unsigned int>(time(nullptr)));
    }

    void init() {
        // 初始化图形窗口
        initgraph(MAP_WIDTH * CELL_SIZE, MAP_HEIGHT * CELL_SIZE);

        // 加载图片
        loadResources();

        // 初始化地图
        map.initMap();

        // 初始化吃豆人位置
        pacman1.x = 15; pacman1.y = 23; pacman1.dir = 1; pacman1.lives = 3; pacman1.score = 0;
        pacman2.x = 15; pacman2.y = 4; pacman2.dir = 3; pacman2.lives = 3; pacman2.score = 0;

        // 初始化幽灵位置
        ghost.x = 15; ghost.y = 12; ghost.dir = 0; ghost.isScared = false; ghost.scaredTimer = 0;
    }

    void loadResources() {
        // 加载吃豆人图片
        loadimage(&pacmanImage1, _T("picture/吃豆人1.png"), CELL_SIZE, CELL_SIZE);
        loadimage(&pacmanImage2, _T("picture/吃豆人3.png"), CELL_SIZE, CELL_SIZE);

        // 加载幽灵图片
        loadimage(&ghostImage, _T("picture/ghost21.png"), CELL_SIZE, CELL_SIZE);

        // 加载害怕状态的幽灵图片
        loadimage(&scaredGhostImage, _T("picture/ghost3.png"), CELL_SIZE, CELL_SIZE);
    }

    void update() {
        if (gameOver || gameWin) return;

        // 处理输入
        handleInput();

        // 移动吃豆人
        movePacman(pacman1);
        movePacman(pacman2);

        // 更新幽灵AI和移动
        updateGhost();

        // 检查碰撞
        checkCollision();

        // 检查游戏状态
        checkGameState();
    }

    void handleInput() {
        // 处理吃豆人1的按键输入（方向键）
        if (GetAsyncKeyState(VK_UP) & 0x8000 && pacman1.dir != 2) pacman1.dir = 0;
        if (GetAsyncKeyState(VK_RIGHT) & 0x8000 && pacman1.dir != 3) pacman1.dir = 1;
        if (GetAsyncKeyState(VK_DOWN) & 0x8000 && pacman1.dir != 0) pacman1.dir = 2;
        if (GetAsyncKeyState(VK_LEFT) & 0x8000 && pacman1.dir != 1) pacman1.dir = 3;

        // 处理吃豆人2的按键输入（WASD）
        if (GetAsyncKeyState('W') & 0x8000 && pacman2.dir != 2) pacman2.dir = 0;
        if (GetAsyncKeyState('D') & 0x8000 && pacman2.dir != 3) pacman2.dir = 1;
        if (GetAsyncKeyState('S') & 0x8000 && pacman2.dir != 0) pacman2.dir = 2;
        if (GetAsyncKeyState('A') & 0x8000 && pacman2.dir != 1) pacman2.dir = 3;
    }

    void movePacman(Pacman& p) {
        int newX = p.x, newY = p.y;
        if (p.dir == 0) newY--;
        if (p.dir == 1) newX++;
        if (p.dir == 2) newY++;
        if (p.dir == 3) newX--;

        // 处理穿墙逻辑
        if (newX < 0) newX = MAP_WIDTH - 1;
        if (newX >= MAP_WIDTH) newX = 0;

        if (map.getElement(newX, newY) != WALL) {
            p.x = newX; p.y = newY;

            // 检查是否吃到豆子或能量豆
            if (map.getElement(p.x, p.y) == BEAN) {
                p.score += 10;
                map.setElement(p.x, p.y, EMPTY);
            }
            else if (map.getElement(p.x, p.y) == ENERGY_BEAN) {
                p.score += 50;
                map.setElement(p.x, p.y, EMPTY);

                // 使幽灵进入害怕状态
                ghost.isScared = true;
                ghost.scaredTimer = 150; // 害怕状态持续时间
            }
        }
    }

    void updateGhost() {
        // 更新幽灵AI
        updateGhostAI(ghost);

        // 移动幽灵
        int newX = ghost.x, newY = ghost.y;
        if (ghost.dir == 0) newY--;
        if (ghost.dir == 1) newX++;
        if (ghost.dir == 2) newY++;
        if (ghost.dir == 3) newX--;

        // 处理穿墙逻辑
        if (newX < 0) newX = MAP_WIDTH - 1;
        if (newX >= MAP_WIDTH) newX = 0;

        if (map.getElement(newX, newY) != WALL) {
            ghost.x = newX; ghost.y = newY;
        }

        // 更新害怕状态计时器
        if (ghost.isScared) {
            ghost.scaredTimer--;
            if (ghost.scaredTimer <= 0) {
                ghost.isScared = false;
            }
        }
    }

    void updateGhostAI(Ghost& g) {
        // 简单AI：追逐离得近的吃豆人
        Pacman* target = &pacman1;
        int dist1 = manhattanDistance(g.x, g.y, pacman1.x, pacman1.y);
        int dist2 = manhattanDistance(g.x, g.y, pacman2.x, pacman2.y);

        if (pacman1.lives <= 0) {
            target = &pacman2;
        }
        else if (pacman2.lives <= 0) {
            target = &pacman1;
        }
        else {
            target = (dist2 < dist1) ? &pacman2 : &pacman1;
        }

        // 实现幽灵的智能寻路
        int bestDir = -1;
        int minDist = INT_MAX;

        // 尝试四个方向
        for (int dir = 0; dir < 4; dir++) {
            // 不能后退
            if ((dir == 0 && g.dir == 2) ||
                (dir == 2 && g.dir == 0) ||
                (dir == 1 && g.dir == 3) ||
                (dir == 3 && g.dir == 1)) {
                continue;
            }

            int newX = g.x, newY = g.y;
            if (dir == 0) newY--;
            if (dir == 1) newX++;
            if (dir == 2) newY++;
            if (dir == 3) newX--;

            // 处理穿墙逻辑
            if (newX < 0) newX = MAP_WIDTH - 1;
            if (newX >= MAP_WIDTH) newX = 0;

            if (map.getElement(newX, newY) != WALL) {
                int dist = manhattanDistance(newX, newY, target->x, target->y);
                if (dist < minDist) {
                    minDist = dist;
                    bestDir = dir;
                }
            }
        }

        if (bestDir != -1) {
            g.dir = bestDir;
        }
    }

    int manhattanDistance(int x1, int y1, int x2, int y2) {
        return abs(x1 - x2) + abs(y1 - y2);
    }

    void checkCollision() {
        // 检查与吃豆人1的碰撞
        if (pacman1.x == ghost.x && pacman1.y == ghost.y && pacman1.lives > 0) {
            if (ghost.isScared) {
                // 幽灵处于害怕状态，被吃掉
                pacman1.score += 200;
                resetGhost(ghost);
            }
            else {
                // 幽灵正常状态，吃豆人死亡
                pacman1.lives--;
                if (pacman1.lives <= 0) {
                    pacman1.x = -1; pacman1.y = -1; // 隐藏吃豆人
                }
                else {
                    resetPacman(pacman1);
                }
            }
        }

        // 检查与吃豆人2的碰撞
        if (pacman2.x == ghost.x && pacman2.y == ghost.y && pacman2.lives > 0) {
            if (ghost.isScared) {
                pacman2.score += 200;
                resetGhost(ghost);
            }
            else {
                pacman2.lives--;
                if (pacman2.lives <= 0) {
                    pacman2.x = -1; pacman2.y = -1; // 隐藏吃豆人
                }
                else {
                    resetPacman(pacman2);
                }
            }
        }
    }

    void resetPacman(Pacman& p) {
        // 根据传入的引用确定是哪个吃豆人
        if (&p == &pacman1) {
            p.x = 15; p.y = 23; p.dir = 1;
        }
        else {
            p.x = 15; p.y = 4; p.dir = 3;
        }
    }

    void resetGhost(Ghost& g) {
        // 重置幽灵位置到幽灵房
        g.x = 15;
        g.y = 12;
        g.dir = rand() % 4;
        g.isScared = false;
        g.scaredTimer = 0;
    }

    void checkGameState() {
        // 检查游戏胜利条件：所有豆子被吃完
        if (map.isMapClear()) {
            gameWin = true;
            return;
        }

        // 检查游戏失败条件：两个吃豆人都没有生命
        if (pacman1.lives <= 0 && pacman2.lives <= 0) {
            gameOver = true;
        }
    }

    void draw() {
        BeginBatchDraw();
        cleardevice();

        // 绘制地图
        map.draw();

        // 绘制吃豆人
        if (pacman1.lives > 0) drawPacman(pacman1, pacmanImage1);
        if (pacman2.lives > 0) drawPacman(pacman2, pacmanImage2);

        // 绘制幽灵
        drawGhost(ghost);

        // 绘制分数和生命值
        drawHUD();

        // 绘制游戏结束或胜利画面
        if (gameOver) {
            drawGameOver();
        }
        else if (gameWin) {
            drawGameWin();
        }

        EndBatchDraw();
    }

    void drawPacman(Pacman& p, IMAGE& img) {
        // 使用透明方式绘制图片
        putimage(p.x * CELL_SIZE, p.y * CELL_SIZE, &img, SRCAND);
        putimage(p.x * CELL_SIZE, p.y * CELL_SIZE, &img, SRCPAINT);
    }

    void drawGhost(Ghost& g) {
        int index = (clock() / 200) % 2;  // 幽灵动画效果

        if (g.isScared) {
            // 绘制害怕状态的幽灵
            putimage(g.x * CELL_SIZE, g.y * CELL_SIZE, &scaredGhostImage, SRCAND);
            putimage(g.x * CELL_SIZE, g.y * CELL_SIZE, &scaredGhostImage, SRCPAINT);
        }
        else {
            // 绘制正常状态的幽灵，交替显示两张图片
            putimage(g.x * CELL_SIZE, g.y * CELL_SIZE, &ghostImage, SRCAND);
            putimage(g.x * CELL_SIZE, g.y * CELL_SIZE, &ghostImage, SRCPAINT);
        }
    }

    void drawHUD() {
        // 设置文字样式
        settextstyle(20, 0, _T("宋体"));
        settextcolor(WHITE);

        // 绘制分数
        TCHAR scoreText[50];
        _stprintf_s(scoreText, _T("Player 1 Score: %d  Lives: %d"), pacman1.score, pacman1.lives);
        outtextxy(10, 10, scoreText);

        _stprintf_s(scoreText, _T("Player 2 Score: %d  Lives: %d"), pacman2.score, pacman2.lives);
        outtextxy(10, 40, scoreText);
    }

    void drawGameOver() {
        setfillcolor(BLACK);
        solidrectangle(MAP_WIDTH * CELL_SIZE / 4, MAP_HEIGHT * CELL_SIZE / 3,
            MAP_WIDTH * CELL_SIZE * 3 / 4, MAP_HEIGHT * CELL_SIZE * 2 / 3);

        settextstyle(40, 0, _T("宋体"));
        settextcolor(RED);
        outtextxy(MAP_WIDTH * CELL_SIZE / 3, MAP_HEIGHT * CELL_SIZE / 2 - 20, _T("GAME OVER"));

        settextstyle(20, 0, _T("宋体"));
        settextcolor(WHITE);
        outtextxy(MAP_WIDTH * CELL_SIZE / 3, MAP_HEIGHT * CELL_SIZE / 2 + 20, _T("Press ESC to exit"));
    }

    void drawGameWin() {
        setfillcolor(BLACK);
        solidrectangle(MAP_WIDTH * CELL_SIZE / 4, MAP_HEIGHT * CELL_SIZE / 3,
            MAP_WIDTH * CELL_SIZE * 3 / 4, MAP_HEIGHT * CELL_SIZE * 2 / 3);

        settextstyle(40, 0, _T("宋体"));
        settextcolor(YELLOW);
        outtextxy(MAP_WIDTH * CELL_SIZE / 3, MAP_HEIGHT * CELL_SIZE / 2 - 20, _T("VICTORY!"));

        settextstyle(20, 0, _T("宋体"));
        settextcolor(WHITE);
        outtextxy(MAP_WIDTH * CELL_SIZE / 3, MAP_HEIGHT * CELL_SIZE / 2 + 20, _T("Press ESC to exit"));
    }

    void run() {
        init();

        // 游戏主循环
        while (true) {
            // 处理退出事件
            if (GetAsyncKeyState(VK_ESCAPE) & 0x8000) {
                break;
            }

            update();
            draw();
            Sleep(80);  // 控制游戏速度
        }
    }
};

int main() {
    Game game;
    game.run();
    closegraph();
    return 0;
}
